import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';

/// ===============================
///  C 侧函数类型定义（FFI桥接）
/// ===============================

/// Speex 编码器初始化函数 (C函数签名)
/// 对应 C 侧：void* speex_encoder_init_wrapper(int quality, int sampleRate);
typedef _SpeexEncoderInit = Pointer<Void> Function(Int32 quality, Int32 sampleRate);
/// Dart 侧对应函数类型（FFI映射用）
typedef _SpeexEncoderInitDart = Pointer<Void> Function(int quality, int sampleRate);

/// Speex 编码一帧函数
/// 对应 C 侧：int speex_encode_frame(void* encoder, short* pcm, unsigned char* output, int maxLen);
typedef _SpeexEncodeFrame = Int32 Function(Pointer<Void> encoder, Pointer<Int16> pcm, Pointer<Uint8> output, Int32 maxLen);
typedef _SpeexEncodeFrameDart = int Function(Pointer<Void> encoder, Pointer<Int16> pcm, Pointer<Uint8> output, int maxLen);

/// 获取 Speex 一帧 PCM 的采样点数
typedef _SpeexGetFrameSize = Int32 Function(Pointer<Void> encoder);
typedef _SpeexGetFrameSizeDart = int Function(Pointer<Void> encoder);

/// 销毁 Speex 编码器实例
typedef _SpeexDestroy = Void Function(Pointer<Void> encoder);
typedef _SpeexDestroyDart = void Function(Pointer<Void> encoder);


/// ====================================
///  Speex 编码器 FFI 封装类（Dart 调用层）
/// ====================================
class SpeexEncoderFFI {
  // 动态库实例（libspeex.so / 系统进程）
  late DynamicLibrary _lib;

  // FFI函数映射到Dart函数
  late _SpeexEncoderInitDart _init;
  late _SpeexEncodeFrameDart _encode;
  late _SpeexGetFrameSizeDart _getFrameSize;
  late _SpeexDestroyDart _destroy;

  // 编码器实例指针（C侧的状态对象）
  Pointer<Void>? _encoder;

  SpeexEncoderFFI() {
    // 根据平台加载动态库
    if (Platform.isAndroid) {
      _lib = DynamicLibrary.open('libspeex.so'); // Android 加载 so 文件
    } else {
      _lib = DynamicLibrary.process(); // iOS/macOS 使用 process()
    }

    // 查找并绑定 C 函数
    _init = _lib.lookupFunction<_SpeexEncoderInit, _SpeexEncoderInitDart>('speex_encoder_init_wrapper');
    _encode = _lib.lookupFunction<_SpeexEncodeFrame, _SpeexEncodeFrameDart>('speex_encode_frame');
    _getFrameSize = _lib.lookupFunction<_SpeexGetFrameSize, _SpeexGetFrameSizeDart>('speex_get_frame_size');
    _destroy = _lib.lookupFunction<_SpeexDestroy, _SpeexDestroyDart>('speex_encoder_destroy');

    // 初始化编码器实例（质量=7，采样率=16kHz）
    // quality 取值范围一般为 0~10，越高压缩率越低但音质越好
    _encoder = _init(7, 16000);
  }

  /// 获取 Speex 每帧对应的 PCM 采样点数量（例如：320 或 160）
  int get frameSize => _getFrameSize(_encoder!);

  /// 编码 PCM 数据为 Speex 数据帧
  Uint8List encode(Uint8List pcmData) {
    // 每个采样点占 2 字节（16bit PCM）
    final frameCount = pcmData.length ~/ 2;

    // 分配 native 内存，用于存放短整型 PCM 数据
    final pcmPtr = malloc.allocate<Int16>(frameCount * sizeOf<Int16>());

    // 将 PCM 数据 (Uint8List) 转为 Int16 格式（小端序）
    final byteData = pcmData.buffer.asByteData();
    for (var i = 0; i < frameCount; i++) {
      pcmPtr[i] = byteData.getInt16(i * 2, Endian.little);
    }

    // 分配输出缓冲区（Speex 压缩后一般几十字节即可，这里给 200 足够）
    const maxLen = 200;
    final outputPtr = malloc.allocate<Uint8>(maxLen);

    // 调用 Speex 编码函数，返回编码后字节长度
    final len = _encode(_encoder!, pcmPtr, outputPtr, maxLen);

    // 取出编码结果（C内存 → Dart内存）
    final encoded = outputPtr.asTypedList(len);
    final copyData = Uint8List.fromList(encoded);

    // 释放 native 内存
    malloc.free(pcmPtr);
    malloc.free(outputPtr);

    // 返回编码后的 Speex 数据帧
    return copyData;
  }

  /// 释放编码器实例
  void dispose() {
    _destroy(_encoder!);
    _encoder = null;
  }
}



/// ====================================
///  Speex 解码器 FFI 封装类
/// ====================================
class SpeexDecoderFFI {
  late DynamicLibrary _lib;

  // FFI 函数绑定
  late Pointer<Void> Function() _init;
  late int Function(Pointer<Void> decoder, Pointer<Int8> input, int len, Pointer<Int16> output) _decode;
  late int Function(Pointer<Void> decoder) _getFrameSize;
  late void Function(Pointer<Void> decoder) _destroy;

  // 解码器实例指针（C侧状态对象）
  Pointer<Void>? _decoder;

  SpeexDecoderFFI() {
    if (Platform.isAndroid) {
      _lib = DynamicLibrary.open('libspeex.so');
    } else {
      _lib = DynamicLibrary.process();
    }

    // 查找并绑定 C 函数
    _init = _lib.lookupFunction<Pointer<Void> Function(), Pointer<Void> Function()>('speex_decoder_init_wrapper');

    _decode = _lib.lookupFunction<
        Int32 Function(Pointer<Void>, Pointer<Int8>, Int32, Pointer<Int16>),
        int Function(Pointer<Void>, Pointer<Int8>, int, Pointer<Int16>)
    >('speex_decode_frame_wrapper');

    _getFrameSize = _lib.lookupFunction<
        Int32 Function(Pointer<Void>),
        int Function(Pointer<Void>)
    >('speex_get_frame_size_decoder');

    _destroy = _lib.lookupFunction<
        Void Function(Pointer<Void>),
        void Function(Pointer<Void>)
    >('speex_decoder_destroy_wrapper');

    // 初始化解码器实例
    _decoder = _init();
  }

  /// 获取解码器每帧对应的 PCM 长度
  int get frameSize => _getFrameSize(_decoder!);

  /// 解码一帧 Speex 裸流数据 → 返回 PCM 数据
  Uint8List decode(Uint8List speexFrame) {
    print("输入pcm长度 = ${speexFrame.length}");
    // 分配内存给 PCM 输出（frameSize * 2 字节）
    final pcmPtr = malloc.allocate<Int16>(frameSize * sizeOf<Int16>());

    // 分配内存给输入数据
    final inputPtr = malloc.allocate<Int8>(speexFrame.length);
    inputPtr.asTypedList(speexFrame.length).setAll(0, speexFrame);

    // 调用解码函数，ret 为解码状态码（负数表示失败）
    final ret = _decode(_decoder!, inputPtr, speexFrame.length, pcmPtr);

    // 将 native PCM 数据复制到 Dart Uint8List（16bit 小端）
    Uint8List pcmBytes = Uint8List(frameSize * 2);
    final byteData = pcmBytes.buffer.asByteData();
    for (var i = 0; i < frameSize; i++) {
      byteData.setInt16(i * 2, pcmPtr[i], Endian.little);
    }

    // 释放 native 内存
    malloc.free(pcmPtr);
    malloc.free(inputPtr);

    // 若解码失败，返回空数据
    if (ret < 0) {
      return Uint8List(0);
    }

    // 返回 PCM 数据帧（可直接播放或送入音频流）
    print(pcmBytes);
    return pcmBytes;
  }

  /// 销毁解码器实例
  void dispose() {
    _destroy(_decoder!);
    _decoder = null;
  }
}
